package com.ruoyi.aitcommon.service;

import java.util.*;

import cn.hutool.core.util.StrUtil;
import com.ruoyi.aitcommon.utils.*;
import org.dom4j.Document;
import org.springframework.stereotype.Service;

import com.ruoyi.aitcommon.anotation.ServiceLog;
import com.ruoyi.aitcommon.vo.AggMap;

/**
 * Map处理类
 * @author Administrator
 *
 */
@Service
public class MapService {
	/**
	 * 将数据集中的某个字段值,从字符串转化为集合
	 * @param datas 数据集合
	 * @param field 需要转换的字段
	 * @param separator 字符串分隔符
	 */
	@ServiceLog("字段转换为集合")
	public List<Map<String,Object>> field2List(List<Map<String,Object>> datas,String field,String separator){
		List<Map<String,Object>> retlist=new ArrayList<>();
		for (Map<String, Object> data : datas) {
			final Object value = data.get(field);
			if(ObjUtils.isNotBlank(value)){
				final List<String> split = StrUtil.split(value.toString(), separator);
				data.put(field,split);
			}
			retlist.add(data);
		}
		return retlist;
	}
	/**
	 * 主子表转换为单表
	 * @param docs 主子表集合
	 * @param lineField 子表名称
	 * @return 主子表拉平后集合,子行字段名=子表名称+字段名
	 */
	@ServiceLog("主子表转换为单表")
	public List<Map<String,Object>> doc2List(List<Map<String,Object>> docs,String lineField) throws Exception {
		List<Map<String, Object>> retlist = new ArrayList<>();

		for (Map<String, Object> doc : docs) {
			//针对单据,每行处理
			if (!doc.containsKey(lineField))
				throw new Exception("doc中不存在字段[" + lineField + "]");
			Object lineValue = doc.get(lineField);
			if (!(lineValue instanceof List))
				throw new Exception("字段[" + lineField + "]类型不是集合");
			List lines = (List) lineValue;
			for (Object line : lines) {
				//针对单据行,每行
				if (!(line instanceof Map))
					throw new Exception("字段[" + lineField + "]类型不是MAP集合");
				Map<String, Object> line1 = (Map<String, Object>) line;
				Map<String, Object> newline = new LinkedHashMap<>();

				for (String key : line1.keySet()) {
					//增对子行 每行每列
					Object value = line1.get(key);
//					String key1=key;
//					if(doc.containsKey(key1)){
////						子行字段重名时处理
//						key1 = lineField + "_" + key1;
//					}
					//子行字段名称=行名称+字段名
					String key1=lineField + "_" + key;
					newline.put(key1, value);
				}
				for (String key : doc.keySet()) {
					//针对单据 每行每列
					if (key.equals(lineField)) continue;
					Object value = doc.get(key);
					newline.put(key, value);
				}
				retlist.add(newline);
			}
		}
		return retlist;
	}

	@ServiceLog("MAP转Xml服务")
	private Document Map2Xml(String rootName,List<Map<String,Object>> maplist) {
		return XmlUtils.Map2Xml(rootName, maplist);
	}
	
	/**
	 * 将Map中的key转化为小写
	 * @param values map集合
	 * @return 转换后的map
	 */
	@ServiceLog("MAP转换服务")
	public List<Map<String,Object>> keyLow(List<Map<String,Object>> values){
		List<Map<String,Object>> retlist = ListMapUtils.newListMap(values, (item)->{
			String key = item.getKey();
			Object value = item.getValue();
			String key1=key.toLowerCase();
			Object[] ret=new Object[] {key1,value};
			return ret;
		});
		return retlist;
	}
	
	/**
	 * 将Map中的key转化为大写
	 * @param values map集合
	 * @return 转换后的map
	 */
	@ServiceLog("MAP转换服务")
	public List<Map<String,Object>> keyUp(List<Map<String,Object>> values){
		List<Map<String,Object>> retlist = ListMapUtils.newListMap(values, (item)->{
			String key = item.getKey();
			Object value = item.getValue();
			String key1=key.toUpperCase();
			Object[] ret=new Object[] {key1,value};
			return ret;
		});
		return retlist;
	}
	
	/**
	 * 将map集合转化为Agg集合
	 * 参照NC AGG模式,Agg包含单头和单体
	 * @param values map集合
	 * @param headkey 单头主键,比如 单号
	 * @param fenge 单头和单体的分隔符,map中必须包含该字段,比如 "fenge"
	 * @return agg集合
	 * @throws Exception
	 */
	@ServiceLog("MAP转换NCC实体服务")
	public List<AggMap> transAggVO(List<Map<String,Object>> values
			,String headkey,String fenge) throws Exception{
		return ListMapUtils.transAggVO(values, headkey, fenge);
	}
	
	/**
	 * 将map集合转化为多层map集合
	 * 参照U9 实体模式,表体作为表头map的属性
	 * @param values map集合
	 * @param fengge 分隔符指定,指定表头表体的分隔,比如:
	 * <pre>
	 * [
			{
				"field": "fengge1",
				"attr": "MiscRcvTransLs",
				"headkey": "DocNo"
			}
		]
	 * </pre>
	 * @param zuhe 组合字段,比如:#,用于将多个字段组合为一个对象
	 * @return 组合后的map对象,比如:
	 * <pre>
	 * [{
        "DocNo":"test",
        "DescFlexField":{
            "PrivateDescSeg1":"111"
        },
        "MiscRcvTransLs":[{
            "ItemInfo":{
                "ItemCode":"0301001.000002"
            },
            "Wh":{
                "Code":"101"
            },
            "StoreUOMQty":20,
            "CostPrice":11
        }]
    }]
	 * </pre>
	 * @throws Exception
	 */
	@ServiceLog("MAP转换U9实体服务")
	public List<Map<String,Object>> transU9Map(List<Map<String,Object>> values
			,List<Map<String,Object>> fengge,String zuhe) throws Exception{
		return ListMapUtils.transU9Map(values, fengge,zuhe);
	}
	
	/**
	 * Map.key的简单映射,将数据中的key替换为映射中的value(key->value)
	 * <pre>
	 * 举例: 
	 * {"OA字段":"这是字段值"}转化为{"U9字段":"这是字段值"}
	 * </pre>
	 * @param datas map集合
	 * @param map key,value转化映射
	 * @return 新map集合
	 */
	@ServiceLog("MAP转换服务")
	public List<Map<String,Object>> transMapKey2Value(List<Map<String,Object>> datas,Map<String,Object> map){
		return ListMapUtils.transObjectKeytoValue(datas, map);
	}
	
	/**
	 * Map.key的简单映射,将数据中的key替换为映射中的key(value->key)
	 * <pre>
	 * 举例: 
	 * {"U9字段":"这是字段值"}转化为{"OA字段":"这是字段值"}
	 * </pre>
	 * @param datas map集合
	 * @param map key,value转化映射
	 * @return 新map集合
	 */
	@ServiceLog("MAP转换服务")
	public List<Map<String,Object>> transMapValue2Key(List<Map<String,Object>> datas,Map<String,Object> map){
		return ListMapUtils.transObjectValuetoKey(datas, map);
	}
	
	/**
	 * 依据映射构造新的map,将datas中的数据填充到entityMap的变量中
	 * @param datas 需要转换的map集合
	 * @param entityMap map映射
	 * <pre>
	 * 举例:
	 * "entityInfo": {
			"code": "${DocNo}",
			"name": "杂收单",
			"type": "杂收单"
		},
	 * </pre>
	 * @return 构造后的新map
	 * @throws Exception
	 */
	@ServiceLog("MAP转换服务")
	public List<Map<String,Object>> transMapParams(List<Map<String,Object>> datas,Map<String,Object> entityMap) throws Exception{
		List<Map<String,Object>> retlist=new ArrayList<Map<String,Object>>();
		ExceptionUtils.checkBlankOrUndefined(entityMap, "entityMap为空");
		for(Map<String,Object> data:datas) {
			Map<String, Object> transMap = FlowParamUtils.getFlowParamsValue(entityMap, data);
			retlist.add(transMap);
		}
		return retlist;
	}

	/**
	 * listMap中所有key的尾部截取处理
	 * 处理场景:
	 * U9传参中表头表体需要传递相同字段.此时需要将表头或表体字段加上尾部代码,如:_wb1
	 * 举例:
	 * values={DocNo=test1, Org_wb1={Code=001}, MiscRcvTransLs=[{Org_wb2={Code=001}, ItemInfo={ItemCode=0301001.000002}, Wh={Code_wb1=101}, StoreUOMQty_wb3=20, CostPrice=11}]}
	 * suffix=["_wb1","_wb2"]
	 * 返回结果:
	 * {DocNo=test1, Org={Code=001}, MiscRcvTransLs=[{Org={Code=001}, ItemInfo={ItemCode=0301001.000002}, Wh={Code=101}, StoreUOMQty_wb3=20, CostPrice=11}]}
	 * @param values agg数据集合
	 * @param suffix 需要去掉的key尾部集合
	 * @return 新的agg数据集合
	 * @throws Exception
	 */
	@ServiceLog("MAP Key尾部处理")
	public List<Map<String,Object>> keySuffix(List<Map<String,Object>> values,List<Object> suffix) throws Exception {
		List<Map<String,Object>> retlist=new ArrayList<>();

		if(suffix==null||suffix.size()==0)
			return values;
		if(values==null||values.size()==0)
			return values;

		for (Map<String, Object> value : values) {
//			调用pathMap,对每个key进行单独处理
			Map<String, Object> retmap = MapUtils.pathMap1(value, (key, val) -> {
				String key1 = key;
//				针对Key,匹配传入的所有suffix尾部字符串
				for (Object item : suffix) {
					if (StrUtil.endWith(key, item.toString())) {
						key1 = StrUtil.removeSuffix(key1, item.toString());
					}
				}

//				返回新的key,value
				return new Object[]{key1, val};
			});

			retlist.add(retmap);
		}
		return retlist;
	}

	@ServiceLog("AGGMAP Key尾部处理")
	public List<AggMap> AggKeySuffix(List<AggMap> values,List<Object> suffix) throws Exception {
		final List<Map<String, Object>> mapList = ListMapUtils.agg2Map(values);
		final List<Map<String, Object>> retlist = this.keySuffix(mapList, suffix);
		final List<AggMap> retaggs = ListMapUtils.map2Agg(retlist);
		return retaggs;
	}

	/**
	 * 将data2的key/value添加到data1的map中
	 * 除了参数key作为匹配项,其它的所有key/value都会从data2复制到data1
	 * @param datas1 data1集合,被添加map集合
	 * @param datas2 data2集合,添加map集合
	 * @param key 唯一键,比如单号docno 或 编码code 等
	 * @return 被添加后的data1集合
	 */
	@ServiceLog("MAP 结构添加")
	public List<Map<String,Object>> ApplyFields(List<Map<String,Object>> datas1
			,List<Map<String,Object>> datas2,String key) throws Exception {
//		将datas2放入缓存
		Map<String,Map<String,Object>> datas2Map=new LinkedHashMap<>();
		for(Map<String,Object> data:datas2){
			if(!data.containsKey(key)){
				throw new Exception("datas2数据中不包含关键字:"+key);
			}
			datas2Map.put(data.get(key).toString(),data);
		}
//		将datas2的数据合并到datas1
		for(Map<String,Object> data:datas1){
			if(!data.containsKey(key)){
				throw new Exception("datas1数据中不包含关键字:"+key);
			}
			if(datas2Map.containsKey(data.get(key))){
				final Map<String, Object> data2 = datas2Map.get(data.get(key));
				for(String key1:data2.keySet()){
					if(key.equals(key1)){
//						关键字不做合并
						continue;
					}
					data.put(key1,data2.get(key1));
				}
			}
		}

		return datas1;
	}

	/**
	 * 将agg2的行集合添加到agg1
	 * @param aggList1 agg1集合,被添加map
	 * @param aggList2 agg2集合,添加map
	 * @param key 唯一键,比如单号docno 或 编码code 等,agg的HEADVO中的字段
	 * @param fieldName agg1中添加的行集合的key
	 * @return 被添加后的agg1集合
	 */
	@ServiceLog("MAP 结构添加")
	public List<AggMap> ApplyAgg(List<AggMap> aggList1,List<AggMap> aggList2
			,String key,String fieldName) throws Exception {
		//		将datas2放入缓存
		Map<String,AggMap> agg2Map=new LinkedHashMap<>();
		for(AggMap agg:aggList2){
			if(!agg.getHeadVO().containsKey(key)){
				throw new Exception("agg2.HeadVO数据中不包含关键字:"+key);
			}
			agg2Map.put(agg.getHeadVO().get(key).toString(),agg);
		}

		//		将datas2的数据合并到datas1
		for(AggMap agg:aggList1){
			if(!agg.getHeadVO().containsKey(key)){
				throw new Exception("agg1.HeadVO数据中不包含关键字:"+key);
			}
			if(agg2Map.containsKey(agg.getHeadVO().get(key))){
				final AggMap agg2 = agg2Map.get(agg.getHeadVO().get(key));
				agg.put(fieldName,agg2.getBodyVOS());
			}
		}

		return aggList1;
	}
}
